﻿using ClassTableService.DTO;
using ClassTableService.Enum;
using System.Reflection;
using System.Text;

namespace ClassTableService.Helper
{
    public class ClassServiceHelper
    {
        //项目路径
        static string[] path = Directory.GetCurrentDirectory().Split('\\');
        //项目名称
        static string nameSpace = path[path.Length - 1];


        #region 实体类生成sql语句

        /// <summary>
        /// 实体类生成sql
        /// </summary>
        /// <param name="serverType">数据库类型</param>
        /// <typeparam name="T">数据类型(实体类)</typeparam>
        /// <returns></returns>
        public static string ClassToSql<T>(ServerTypeEnum serverType)
        {
            //属性信息
            Dictionary<string, string> propertKeyValue = new Dictionary<string, string>();
            //sql语句
            string sql = string.Empty;

            //获取T实体的数据
            //取出T的type
            Type type = typeof(T);
            //获取T实体类中的属性名称、类型
            PropertyInfo[] property = type.GetProperties();
            foreach (var item in property)
            {
                propertKeyValue.Add(item.Name, item.PropertyType.Name);
            }

            //数据绑定
            sql = SqlJoin(propertKeyValue, type.Name, serverType);

            return sql;
        }

        /// <summary>
        /// 校验字段类型
        /// </summary>
        /// <param name="type">数据类型</param>
        /// <param name="serverType">数据库类型</param>
        /// <returns>对应的数据库字段类型</returns>
        public static string VerifyPropertType(string type, ServerTypeEnum serverType)
        {
            string result = string.Empty;

            result = serverType switch
            {
                ServerTypeEnum.MySql => type switch
                {
                    "Int32" => "int(0)",
                    "int" => "int(0)",
                    "Boolean" => "int(0)",
                    "bool" => "int(0)",
                    "String" => "varchar(255)",
                    "string" => "varchar(255)",
                    "DateTime" => "datetime(0)",
                    "dateTime" => "datetime(0)",
                    "Double" => "double",
                    "double" => "double",
                    _ => string.Empty
                },
                ServerTypeEnum.SqlServer => type switch
                {
                    "Int32" => "int",
                    "int" => "int",
                    "Boolean" => "int",
                    "bool" => "int",
                    "String" => "nvarchar(255)",
                    "string" => "nvarchar(255)",
                    "DateTime" => "datetime",
                    "dateTime" => "datetime",
                    "Double" => "decimal(18)",
                    "double" => "decimal(18)",
                    _ => string.Empty
                },
                ServerTypeEnum.Sqlite => type switch
                {
                    "Int32" => "integer(32)",
                    "int" => "integer(32)",
                    "Boolean" => "integer(2)",
                    "bool" => "integer(2)",
                    "String" => "TEXT(40)",
                    "string" => "TEXT(40)",
                    "DateTime" => "TEXT(40)",
                    "dateTime" => "TEXT(40)",
                    "Double" => "real(40)",
                    "double" => "real(40)",
                    _ => string.Empty
                },
                _ => string.Empty
            };
            return result;
        }

        /// <summary>
        /// Sql语句拼接
        /// </summary>
        /// <param name="data">属性-类型 字典</param>
        /// <param name="tableName">实体类名-表名</param>
        /// <param name="serverType">数据库类型</param>
        /// <returns>创建数据库:表、字段的SQL语句</returns>
        public static string SqlJoin(Dictionary<string, string> data, string tableName, ServerTypeEnum serverType)
        {
            //sql语句
            string sql = string.Empty;
            //主键属性
            string PrimaryKey = string.Empty;
            //是否是第一个字段
            bool isFirst = true;

            switch (serverType)
            {
                case ServerTypeEnum.MySql:  //MySql数据库
                    //拼接表名
                    sql += $"DROP TABLE IF EXISTS `{tableName}`; " +
                        $"CREATE TABLE `{tableName}`(";

                    //拼接字段
                    foreach (var item in data)
                    {
                        //是否是第一个字段,第一个字段默认主键
                        if (isFirst)
                        {
                            PrimaryKey = item.Key;
                            isFirst = false;
                        }

                        //数据库字段类型
                        string servicePropertType = VerifyPropertType(item.Value, ServerTypeEnum.MySql);

                        //判断属性类型是否识别
                        if (!string.IsNullOrEmpty(servicePropertType))
                        {
                            //识别，拼接sql
                            sql += $@"`{item.Key}` {servicePropertType},";
                        }
                        else
                        {
                            return "拥有未知类型!";
                        }
                    }

                    sql += $" PRIMARY KEY (`{PrimaryKey}`) USING BTREE);";

                    break;
                case ServerTypeEnum.SqlServer:  //SqlServer数据库
                    //拼接表名
                    sql += $"IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[{tableName}]') AND type IN ('U')) " +
                        $"DROP TABLE [dbo].[{tableName}] " +
                        $"CREATE TABLE [dbo].[{tableName}] (";

                    //拼接字段
                    foreach (var item in data)
                    {
                        //是否是第一个字段,第一个字段默认主键
                        if (isFirst)
                        {
                            PrimaryKey = item.Key;
                            isFirst = false;
                        }

                        //数据库字段类型
                        string servicePropertType = VerifyPropertType(item.Value, ServerTypeEnum.SqlServer);

                        //判断属性类型是否识别
                        if (!string.IsNullOrEmpty(servicePropertType))
                        {
                            //识别，拼接sql
                            sql += $@"[{item.Key}] {servicePropertType},";
                        }
                        else
                        {
                            return "拥有未知类型!";
                        }
                    }

                    sql += $" PRIMARY KEY ([{PrimaryKey}]));";

                    break;
                case ServerTypeEnum.Sqlite: //Sqlite
                    //拼接表名
                    sql += $"DROP TABLE IF EXISTS `{tableName}`; " +
                        $"CREATE TABLE `{tableName}` (";

                    //拼接字段
                    foreach (var item in data)
                    {
                        //数据库字段类型
                        string servicePropertType = VerifyPropertType(item.Value, ServerTypeEnum.Sqlite);

                        //是否是第一个字段,第一个字段默认主键
                        if (isFirst)
                        {
                            PrimaryKey = item.Key;
                            isFirst = false;
                            if (!string.IsNullOrEmpty(servicePropertType))
                            {
                                servicePropertType += " NOT NULL";
                            }
                        }

                        //判断属性类型是否识别
                        if (!string.IsNullOrEmpty(servicePropertType))
                        {
                            //识别，拼接sql
                            sql += $"`{item.Key}` {servicePropertType},";
                        }
                        else
                        {
                            return "拥有未知类型!";
                        }
                    }

                    sql += $" PRIMARY KEY (`{PrimaryKey}`));";

                    break;
                default:
                    return null;
            }
            return sql;
        }

        #endregion



        #region 生成实体类cs文件

        /// <summary>
        /// 生成实体类cs文件
        /// 可以生成多个实体类
        /// </summary>
        /// <param name="data">实体类字典:key:类名，value:属性名、类型、备注</param>
        /// <returns></returns>
        public static int CreateClassFie(Dictionary<string, List<GenericClassDTO>> data)
        {
            try
            {
                if (data == null || data.Count <= 0) return -1;

                StringBuilder stringBuilder = new StringBuilder();
                foreach (var item in data)
                {
                    ////引入命空间
                    //stringBuilder.AppendLine($"using system;");
                    //stringBuilder.AppendLine();
                    //默认命名空间为项目名称，把实体类生成到项目目录中
                    stringBuilder.AppendLine($"namespace {nameSpace}");
                    stringBuilder.AppendLine("{");
                    stringBuilder.AppendLine($"    public class {item.Key}");
                    stringBuilder.AppendLine("    {");
                    foreach (var propert in item.Value)
                    {
                        stringBuilder.AppendLine("        /// <summary>");
                        stringBuilder.AppendLine($"        /// {propert.PropertRemark}");
                        stringBuilder.AppendLine("        /// <summary>");
                        stringBuilder.AppendLine($"        public {propert.PropertType} {propert.PropertName} {{ get;set; }}");
                        stringBuilder.AppendLine();
                    }
                    stringBuilder.AppendLine("    }");
                    stringBuilder.AppendLine("}");

                    //该文件的输出路径
                    string outputPath = Directory.GetCurrentDirectory() + "\\Model\\" + item.Key + ".cs";
                    System.IO.File.AppendAllText(outputPath, stringBuilder.ToString());
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("生成实体类cs文件异常：" + ex.Message);
                return -2;
            }
            return 200;
        }

        #endregion



        #region 一键生成实体类和sql

        /// <summary>
        /// 生成实体类cs文件 和 创建数据表的sql语句
        /// 可以生成多个实体类
        /// </summary>
        /// <param name="data">实体类字典:key:类名，value:属性名、类型、备注</param>
        /// <returns></returns>
        public static int CreateClassFieAndSql(CreateClassFileAndSqlDTO data, ServerTypeEnum serverType, out string sql)
        {
            sql = null;
            try
            {
                if (data == null) return -1;

                //属性信息
                Dictionary<string, string> propertKeyValue = new Dictionary<string, string>();
                //创建表sql语句

                //实例化一个可变字符串用于拼接生成的实体类信息
                StringBuilder stringBuilder = new StringBuilder();

                //默认命名空间为项目名称，把实体类生成到项目目录中
                stringBuilder.AppendLine($"namespace {nameSpace}");
                stringBuilder.AppendLine("{");
                stringBuilder.AppendLine($"    public class {data.TableName}");
                stringBuilder.AppendLine("    {");
                foreach (var propert in data.Properties)
                {
                    stringBuilder.AppendLine("        /// <summary>");
                    stringBuilder.AppendLine($"        /// {propert.PropertRemark}");
                    stringBuilder.AppendLine("        /// <summary>");
                    stringBuilder.AppendLine($"        public {propert.PropertType} {propert.PropertName} {{ get;set; }}");
                    stringBuilder.AppendLine();

                    //属性值信息
                    propertKeyValue.Add(propert.PropertName, propert.PropertType);
                }
                stringBuilder.AppendLine("    }");
                stringBuilder.AppendLine("}");

                //该文件的输出路径
                string outputPath = Directory.GetCurrentDirectory() + "\\Model\\" + data.TableName + ".cs";
                System.IO.File.AppendAllText(outputPath, stringBuilder.ToString());

                //sql语句拼接
                sql = SqlJoin(propertKeyValue, data.TableName, serverType);
            }
            catch (Exception ex)
            {
                Console.WriteLine("生成实体类cs文件异常：" + ex.Message);
                return -2;
            }
            return 200;
        }

        #endregion


    }
}
